﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Text.RegularExpressions;
using SLua;

public static class UnityExt
{
    #region Transform
    public static void InitTransform(this Component cmpt)
    {
        Transform trans = cmpt.transform;
        trans.localPosition = Vector3.zero;
        trans.localRotation = Quaternion.identity;
        trans.localScale = Vector3.one;
    }

    #region active / parent
    public static void SetActive(this Component cmpt, bool bActive)
    {
        cmpt.gameObject.SetActive(bActive);
    }
    public static void SetParentPure(this Component cmpt, Component parent)
    {
        cmpt.transform.SetParent(parent.transform);
    }
    public static void SetParentPure(this GameObject obj, Component parent)
    {
        obj.transform.SetParent(parent.transform);
    }

    public static void SetParentEx(this Component cmpt, Component parent)
    {
        LuaHelper.SetParent(cmpt.transform, parent);
    }
    public static void SetParentEx(this GameObject obj, Component parent)
    {
        LuaHelper.SetParent(obj.transform, parent);
    }
    #endregion

    #region local position
    //-----------读取相对位置
    public static void SetLocalPositionZero(this Component cmpt)
    {
        cmpt.transform.localPosition = Vector3.zero;
    }

    public static void SetLocalPositionEx(this Component cmpt, float x, float y, float z)
    {
        cmpt.transform.localPosition = new Vector3(x, y, z);
    }
    public static void SetLocalPosition(this Component cmpt, Vector3 pos)
    {
        cmpt.transform.localPosition = pos;
    }

    public static void SetLocalPositionX(this Component cmpt, float x)
    {
        Vector3 pos = cmpt.transform.localPosition;
        pos.x = x;
        cmpt.transform.localPosition = pos;
    }
    public static void SetLocalPositionY(this Component cmpt, float y)
    {
        Vector3 pos = cmpt.transform.localPosition;
        pos.y = y;
        cmpt.transform.localPosition = pos;
    }
    public static void SetLocalPositionZ(this Component cmpt, float z)
    {
        Vector3 pos = cmpt.transform.localPosition;
        pos.z = z;
        cmpt.transform.localPosition = pos;
    }
    public static void SetLocalPositionFromTarget(this Component cmpt, Transform target)
    {
        cmpt.transform.localPosition = target.localPosition;
    }
    public static Vector3 GetLocalPosition(this Component cmpt)
    {
        return cmpt.transform.localPosition;
    }
    public static void GetLocalPositionEx(this Component cmpt, out float x, out float y, out float z)
    {
        Transform trans = cmpt.transform;
        x = trans.localPosition.x;
        y = trans.localPosition.y;
        z = trans.localPosition.z;
    }
    public static float GetLocalPositionX(this Component cmpt)
    {
        return cmpt.transform.localPosition.x;
    }
    public static float GetLocalPositionY(this Component cmpt)
    {
        return cmpt.transform.localPosition.y;
    }
    #endregion

    #region world position
    //-----------读取世界坐标位置
    public static void SetPostionZero(this Component cmpt)
    {
        cmpt.transform.position = Vector3.zero;
    }
    public static void SetPositionEx(this Component cmpt, float x, float y, float z)
    {
        cmpt.transform.position = new Vector3(x, y, z);
    }
    public static void SetPosition(this Component cmpt, Vector3 pos)
    {
        cmpt.transform.position = pos;
    }

    public static void SetPositionX(this Component cmpt, float x)
    {
        Vector3 pos = cmpt.transform.position;
        pos.x = x;
        cmpt.transform.position = pos;
    }
    public static void SetPositionY(this Component cmpt, float y)
    {
        Vector3 pos = cmpt.transform.position;
        pos.y = y;
        cmpt.transform.position = pos;
    }

    public static void SetPositionZ(this Component cmpt, float z)
    {
        Vector3 pos = cmpt.transform.position;
        pos.z = z;
        cmpt.transform.position = pos;
    }

    public static void SetPositionFromTarget(this Component cmpt, Transform target)
    {
        cmpt.transform.position = target.position;
    }
    public static Vector3 GetPosition(this Component cmpt)
    {
        return cmpt.transform.position;
    }
    public static Vector3 GetPosition(this GameObject obj)
    {
        return obj.transform.position;
    }
    public static float GetPositionY(this Component cmpt)
    {
        return cmpt.transform.position.y;
    }

    public static void GetPositionEx(this Component cmpt, out float x, out float y, out float z)
    {
        Transform trans = cmpt.transform;
        x = trans.position.x;
        y = trans.position.y;
        z = trans.position.z;
    }
    #endregion

    #region local scale
    //----------------缩放
    public static void SetLocalScaleZero(this Component cmpt)
    {
        cmpt.transform.localScale = Vector3.zero;
    }
    public static void SetLocalScaleOne(this Component cmpt)
    {
        cmpt.transform.localScale = Vector3.one;
    }
    public static void SetLocalScaleEx(this Component cmpt, float x, float y, float z)
    {
        cmpt.transform.localScale = new Vector3(x, y, z);
    }
    public static void SetLocalScale(this Component cmpt, Vector3 scale)
    {
        cmpt.transform.localScale = scale;
    }
    public static void SetLocalScaleVal(this Component cmpt, float val)
    {
        cmpt.transform.localScale = new Vector3(val, val, val);
    }
    public static void SetLocalScaleY(this Component cmpt, float y)
    {
        Vector3 scale = cmpt.transform.localScale;
        scale.y = y;
        cmpt.transform.localScale = scale;
    }
    public static void SetLocalScaleX(this Component cmpt, float x)
    {
        Vector3 scale = cmpt.transform.localScale;
        scale.x = x;
        cmpt.transform.localScale = scale;
    }
    public static Vector3 GetLocalScale(this Component cmpt)
    {
        return cmpt.transform.localScale;
    }
    public static void GetLocalScaleEx(this Component cmpt, out float x, out float y, out float z)
    {
        Transform trans = cmpt.transform;
        x = trans.localScale.x;
        y = trans.localScale.y;
        z = trans.localScale.z;
    }
    public static float GetLocalScaleX(this Component cmpt)
    {
        return cmpt.transform.localScale.x;
    }
    #endregion

    #region  rotation
    //-----------------旋转
    public static void SetLocalRotationOne(this Component cmpt)
    {
        cmpt.transform.rotation = Quaternion.identity;
    }
    public static void SetLocalEulerAngle(this Component cmpt, float x, float y, float z)
    {
        cmpt.transform.localRotation = Quaternion.Euler(new Vector3(x, y, z));
    }
    public static void SetLocalEulerAngleZ(this Component cmpt, float z)
    {
        var v3 = cmpt.transform.localEulerAngles;
        v3.z = z;
        cmpt.transform.localEulerAngles = v3;
    }
    public static void SetLocalEulerAngleY(this Component cmpt, float y)
    {
        var v3 = cmpt.transform.localEulerAngles;
        v3.y = y;
        cmpt.transform.localEulerAngles = v3;
    }

    public static void GetLocalEulerAngle(this Component cmpt, out float x, out float y, out float z)
    {
        Transform trans = cmpt.transform;
        x = trans.localEulerAngles.x;
        y = trans.localEulerAngles.y;
        z = trans.localEulerAngles.z;
    }
    public static Vector3 GetEulerAngle(this Component cmpt)
    {
        return cmpt.transform.rotation.eulerAngles;
    }
    public static float GetEulerAngleY(this Component cmpt)
    {
        return cmpt.transform.rotation.eulerAngles.y;
    }
    public static float GetLocalEulerAngleX(this Component cmpt)
    {
        return cmpt.transform.localRotation.eulerAngles.x;
    }
    public static float GetLocalEulerAngleY(this Component cmpt)
    {
        return cmpt.transform.localRotation.eulerAngles.y;
    }
    public static float GetLocalEulerAngleZ(this Component cmpt)
    {
        return cmpt.transform.localRotation.eulerAngles.z;
    }

    public static void RotateAxisY(this Component cmpt, float y, Space relativeTo = Space.Self)
    {
        cmpt.transform.Rotate(0, y, 0, relativeTo);
    }
    #endregion

    #endregion

    #region RectTransfrom
    public static void SetSizeDelta(this Component cmpt, Vector2 size)
    {
        RectTransform rectTrans = cmpt.transform as RectTransform;
        rectTrans.sizeDelta = size;
    }

    public static void SetSizeDeltaEx(this Component cmpt, float x, float y)
    {
        RectTransform rectTrans = cmpt.transform as RectTransform;
        rectTrans.sizeDelta = new Vector2(x, y);
    }

    public static void SetSizeDeltaX(this Component cmpt, float x)
    {
        RectTransform rectTrans = cmpt.transform as RectTransform;
        rectTrans.sizeDelta = new Vector2(x, rectTrans.sizeDelta.y);
    }

    public static void SetSizeDeltaY(this Component cmpt, float y)
    {
        RectTransform rectTrans = cmpt.transform as RectTransform;
        rectTrans.sizeDelta = new Vector2(rectTrans.sizeDelta.x, y);
    }

    public static void GetSizeDeltaEx(this Component cmpt, out float x, out float y)
    {
        RectTransform rectTrans = cmpt.transform as RectTransform;
        x = rectTrans.sizeDelta.x;
        y = rectTrans.sizeDelta.y;
    }

    public static void GetSizeDeltaX(this Component cmpt, out float x)
    {
        x = (cmpt.transform as RectTransform).sizeDelta.x;
    }

    public static void GetSizeDeltaY(this Component cmpt, out float y)
    {
        y = (cmpt.transform as RectTransform).sizeDelta.y;
    }

    public static void GetAnchoredPosition(this Component cmpt, out float x, out float y)
    {
        RectTransform rectTrans = cmpt.transform as RectTransform;
        x = rectTrans.anchoredPosition.x;
        y = rectTrans.anchoredPosition.y;
    }
    public static void GetAnchoredPositionX(this Component cmpt, out float x)
    {
        x = (cmpt.transform as RectTransform).anchoredPosition.x;
    }

    public static void GetAnchoredPositionY(this Component cmpt, out float y)
    {
        y = (cmpt.transform as RectTransform).anchoredPosition.y;
    }

    public static void SetAnchoredPosition(this Component cmpt, Vector2 pos)
    {
        (cmpt.transform as RectTransform).anchoredPosition = pos;
    }
    public static void SetAnchoredPositionEx(this Component cmpt, float x, float y)
    {
        (cmpt.transform as RectTransform).anchoredPosition = new Vector2(x, y);
    }


    public static void SetAnchoredPositionX(this Component cmpt, float x)
    {
        RectTransform rectTrans = cmpt.transform as RectTransform;
        rectTrans.anchoredPosition = new Vector2(x, rectTrans.anchoredPosition.y);
    }

    public static void SetAnchoredPositionY(this Component cmpt, float y)
    {
        RectTransform rectTrans = cmpt.transform as RectTransform;
        rectTrans.anchoredPosition = new Vector2(rectTrans.anchoredPosition.x, y);
    }

    public static float GetRectWidth(this Component cmpt)
    {
        RectTransform rectTrans = cmpt.transform as RectTransform;
        return rectTrans.rect.width;
    }

    public static void GetRectHeight(this Component cmpt, out float height)
    {
        RectTransform rectTrans = cmpt.transform as RectTransform;
        height = rectTrans.rect.height;
    }

    public static void GetRectSize(this Component cmpt, out float width, out float height)
    {
        RectTransform rectTrans = cmpt.transform as RectTransform;
        width = rectTrans.rect.width;
        height = rectTrans.rect.height;
    }

    public static void SetFontColor(this Text txt, float r, float g, float b, float a)
    {
        txt.color = new Color(r, g, b, a);
    }

    public static Vector2 TransformToCanvasLocalPosition(this Transform current, Canvas canvas)
    {
        var screenPos = canvas.worldCamera.WorldToScreenPoint(current.transform.position);
        Vector2 localPos;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.GetComponent<RectTransform>(), screenPos, canvas.worldCamera, out localPos);
        return localPos;
    }

    public static void SetAnchor(this RectTransform cmpt, TextAnchor anchor)
    {
        switch (anchor)
        {
            case TextAnchor.UpperRight:
                cmpt.anchorMin = new Vector2(1f, 1f);
                cmpt.anchorMax = new Vector2(1f, 1f);
                break;
            case TextAnchor.UpperCenter:
                cmpt.anchorMin = new Vector2(0.5f, 1f);
                cmpt.anchorMax = new Vector2(0.5f, 1f);
                break;
            case TextAnchor.UpperLeft:
                cmpt.anchorMin = new Vector2(0f, 1f);
                cmpt.anchorMax = new Vector2(0f, 1f);
                break;
            case TextAnchor.MiddleLeft:
                cmpt.anchorMin = new Vector2(0f, 0.5f);
                cmpt.anchorMax = new Vector2(0f, 0.5f);
                break;
            case TextAnchor.MiddleCenter:
                cmpt.anchorMin = new Vector2(0.5f, 0.5f);
                cmpt.anchorMax = new Vector2(0.5f, 0.5f);
                break;
            case TextAnchor.MiddleRight:
                cmpt.anchorMin = new Vector2(1f, 0.5f);
                cmpt.anchorMax = new Vector2(1f, 0.5f);
                break;
            case TextAnchor.LowerLeft:
                cmpt.anchorMin = new Vector2(0f, 0f);
                cmpt.anchorMax = new Vector2(0f, 0f);
                break;
            case TextAnchor.LowerCenter:
                cmpt.anchorMin = new Vector2(0.5f, 0f);
                cmpt.anchorMax = new Vector2(0.5f, 0f);
                break;
            case TextAnchor.LowerRight:
                cmpt.anchorMin = new Vector2(1f, 0f);
                cmpt.anchorMax = new Vector2(1f, 0f);
                break;
        }
    }

    public static void SetAnchor(this RectTransform cmpt, int a)
    {
        SetAnchor(cmpt, (TextAnchor)a);
    }

    public static void SetRectOffset(this RectTransform cmpt, float left, float right, float up, float bottom)
    {
        cmpt.offsetMin = new Vector2(left, bottom);
        cmpt.offsetMax = new Vector2(right, up);
    }
    #endregion

    #region graphic
    public static void SetGraphicAlpha(this Graphic gp, float a)
    {
        Color clr = gp.color;
        clr.a = a;
        gp.color = clr;
    }
    public static void SetRaycastTarget(this Component cmpt, bool isTarget)
    {
        Graphic gp = cmpt.GetComponent<Graphic>();
        if (gp != null)
        {
            gp.raycastTarget = isTarget;
        }
    }
    public static void SetActive(this SDImage img, bool bActive)
    {
        var cull = img.m_Cull;
        if (cull != !bActive)
        {
            img.m_Cull = !bActive;
        }
    }
    public static void SetActive(this SDImage img, bool bActive, bool isRealActive)
    {
        if (isRealActive)
        {
            img.gameObject.SetActive(bActive);
        }
        else
        {
            var cull = img.m_Cull;
            if (cull != !bActive)
            {
                img.m_Cull = !bActive;
            }
        }
    }
    public static void SetActive(this SoarDText text, bool bActive)
    {
        var cull = text.m_Cull;
        if (cull != !bActive)
        {
            text.m_Cull = !bActive;
        }
    }
    public static void SetActive(this SoarDText text, bool bActive, bool isRealActive)
    {
        if (isRealActive)
        {
            text.gameObject.SetActive(bActive);
        }
        else
        {
            var cull = text.m_Cull;
            if (cull != !bActive)
            {
                text.m_Cull = !bActive;
            }
        }
    }
#if UNITY_EDITOR
    [DoNotToLua]
    public static void SetActive(this Graphic gp, bool bActive)
    {
        if (gp is SDImage)
        {
            var img = (gp as SDImage);
            img.SetActive(bActive);
        }
        else if (gp is SoarDText)
        {
            var text = (gp as SoarDText);
            text.SetActive(bActive);
        }
        else
        {
            gp.gameObject.SetActive(bActive);
        }
    }
#endif
    #endregion

    #region 位置相关计算
    public static float DistanceLocalToPos(this Transform trans, Vector3 pos)
    {
        return Vector3.Distance(trans.localPosition, pos);
    }
    public static float DistanceToPos(this Transform trans, Vector3 pos)
    {
        return Vector3.Distance(trans.position, pos);
    }

    public static float DistanceToTarget(this Transform trans, Transform target)
    {
        return Vector3.Distance(trans.position, target.position);
    }

    //距离的平方，只是用来作比较的时候可以节省性能
    public static float SqrDisToPos(this Transform trans, Vector3 pos)
    {
        Vector3 disVec = pos - trans.position;
        return disVec.sqrMagnitude;
    }


    public static float AngleYLocalToPos(this Transform trans, Vector3 pos)
    {
        Vector3 delta = pos - trans.localPosition;
        float angle = Mathf.Rad2Deg * (Mathf.Atan2(delta.z, delta.x));
        return angle;
    }

    #endregion

    #region 国际化
    /// <summary>
    /// 重置LangItem
    /// </summary>
    /// <param name="mtran"></param>
    public static void ResetLangItem(this Component cmpt)
    {
        //获取子对象组件
        UILangItem[] items = cmpt.transform.GetComponentsInChildren<UILangItem>(true);
        for (int i = 0, len = items.Length; i < len; i++)
        {
            items[i].SetText();
        }
    }

    public static string[] GetPath(this Component cmpt, Transform parent)
    {
        List<string> paths = new List<string>();
        Transform child = cmpt.transform;
        while (child.parent && child.parent != parent)
        {
            paths.Add(child.name);
            child = child.parent;
        }
        paths.Reverse();
        return paths.ToArray();
    }
    #endregion

    #region UI

    #region Text
    public static void SetTextMaxWidth(this Component cmpt, float width)
    {
        if (width <= 0) return;
        UITextLimit textLimit = cmpt.gameObject.GetComponent<UITextLimit>();
        if (textLimit == null)
            textLimit = cmpt.gameObject.AddComponent<UITextLimit>();
        textLimit.MaxWidth = width;
    }

    // 获取指定Text组件条件下指定任意内容的最佳高度
    public static float GetOneTextPreferredHeight(this Text text, string content)
    {
        if (!string.IsNullOrEmpty(content))
        {
            TextGenerator tg = text.cachedTextGenerator;
            Rect rect = text.rectTransform.rect;
            TextGenerationSettings tgs = text.GetGenerationSettings(rect.size);
            float originalHeight = tg.GetPreferredHeight(content, tgs);

            return originalHeight / text.pixelsPerUnit;
        }

        return 0;
    }

    // 获取指定Text组件条件下多个指定内容的最佳高度集合
    public static float[] GetTextsPreferredHeight(this Text text, string[] contents)
    {
        float[] heights = new float[contents.Length];
        TextGenerator tg = text.cachedTextGenerator;
        Rect rect = text.rectTransform.rect;
        TextGenerationSettings tgs = text.GetGenerationSettings(rect.size);

        float pixelsPerUnit = text.pixelsPerUnit;
        for (int i = 0; i < contents.Length; i++)
        {
            if (string.IsNullOrEmpty(contents[i]))
                heights[i] = 0;
            else
                heights[i] = tg.GetPreferredHeight(contents[i], tgs) / pixelsPerUnit;
        }

        return heights;
    }

    // 设置文本内容，且设置最佳高度
    public static void SetTextAndPreferredHeight(this Text text, string content)
    {
        if (content != null)
        {
            text.text = content;
            float preferredHeight = text.preferredHeight;
            text.SetSizeDeltaY(preferredHeight);
        }
    }

    // 设置文本内容，设置最佳高度，并返回最佳高度
    public static float GetSetTextPreferredHeight(this Text text, string content)
    {
        float preferredHeight = 0;
        if (content != null)
        {
            text.text = content;
            preferredHeight = text.preferredHeight;
            text.SetSizeDeltaY(preferredHeight);
        }
        return preferredHeight;
    }

    //设置文本内容，且设置最佳宽度
    public static void SetTextAndPreferredWidth(this Text text, string content)
    {
        if(content!=null)
        {
            text.text = content;
            float preferredWidth = text.preferredWidth;
            text.SetSizeDeltaX(preferredWidth);
        }
    }

    //设置文本内容，设置最佳宽度，并返回最佳宽度
    public static float GetSetTextPreferredWidth(this Text text, string content)
    {
        float preferredWidth = 0;
        if (content != null)
        {
            text.text = content;
            preferredWidth = text.preferredWidth;
            text.SetSizeDeltaX(preferredWidth);
        }
        return preferredWidth;
    }

    //设置一个组件所在对象上的所有Shadow组件的Color
    public static void SetShadowsColor(this Component cmpt, Color color)
    {
        Shadow[]  shadows = cmpt.GetComponents<Shadow>();
        if(shadows!=null)
        {
            for(int i = 0; i < shadows.Length; i++)
            {
                shadows[i].effectColor = color;
            }
        }
    }

    public static void SetLayoutSize(this Component cmpt)
    {
        SetLayoutSize(cmpt, 0, 0);
    }

    public static void SetLayoutSize(this Component cmpt, float width, float height)
    {
        if (cmpt != null)
        {
            LayoutElement element = cmpt.GetComponent<LayoutElement>();
            if (width <= float.Epsilon && height <= float.Epsilon)
            {
                if (cmpt is SDImage)
                {
                    SDImage image = cmpt as SDImage;
                    element.preferredWidth = image.preferredWidth;
                    element.preferredHeight = image.preferredHeight;
                }
            }
            else
            {
                element.preferredWidth = width;
                element.preferredHeight = height;
            }
        }
    }
    #endregion

    public static int GetLayoutGroupPaddingTop(this Component cmpt)
    {
        LayoutGroup lg = cmpt.GetComponent<LayoutGroup>();
        if(lg != null)
            return lg.padding.top;

        return 0;            
    }

    public static float GetHorizontalOrVerticalLayoutGroupSpacing(this Component cmpt)
    {
        HorizontalOrVerticalLayoutGroup lg = cmpt.GetComponent<HorizontalOrVerticalLayoutGroup>();
        if(lg != null)
            return lg.spacing;

        return 0f;        
    }
    #endregion

    #region Renderer

    public static void SetMaterialFloat(this Material mat, string propertyName, float value)
    {
        if (mat != null)
            mat.SetFloat(propertyName, value);
    }

    #endregion

    #region ShowHide

    public static void ShowHideByScale(this Component cmpt, bool isShow)
    {
        if (isShow)
            cmpt.SetLocalScaleOne();
        else
            cmpt.SetLocalScaleZero();
    }

    #endregion

    public static RectTransform rectTransform(this Component cp)
    {
        return cp.transform as RectTransform;
    }

    public static void SetWidth(this RectTransform rt, float width)
    {
        rt.sizeDelta = new Vector2(width, rt.sizeDelta.y);
    }

    public static float Remap(this float value, float from1, float to1, float from2, float to2)
    {
        return (value - from1) / (to1 - from1) * (to2 - from2) + from2;
    }
}